package skewreduce.lib;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;

import org.apache.hadoop.io.Writable;

public class Point3D implements Writable, IPoint3D {
    protected float x;
    protected float y;
    protected float z;

    public Point3D() {}

    public static Point3D getInfinity() {
        return new Point3D(Float.MAX_VALUE,Float.MAX_VALUE,Float.MAX_VALUE);
    }
    public static Point3D getNegInfinity() {
        return new Point3D(-1.0f*Float.MAX_VALUE,-1.0f*Float.MAX_VALUE,-1.0f*Float.MAX_VALUE);
    }

    public Point3D(String spec) {
        String[] coords = spec.split(",");
        if ( coords == null || coords.length != 3 )
            throw new IllegalArgumentException(spec);
        x = Float.parseFloat(coords[0]);
        y = Float.parseFloat(coords[1]);
        z = Float.parseFloat(coords[2]);
    }

    public Point3D(IPoint3D p) {
        x = p.getX(); y = p.getY(); z = p.getZ();
    }
    
    public Point3D(java.util.Random r) {
        x = r.nextFloat(); y = r.nextFloat(); z = r.nextFloat();
    }

    public Point3D(float x,float y,float z) {
        this.x = x;
        this.y = y;
        this.z = z;
    }

    public float getX() { return x; }
    public float getY() { return y; }
    public float getZ() { return z; }

    public void setX(float c) { x = c; }
    public void setY(float c) { y = c; }
    public void setZ(float c) { z = c; }

    public final double distance(IPoint3D o) {
        if ( this == o ) return 0.0;
        double dx = x - o.getX();
        double dy = y - o.getY();
        double dz = z - o.getZ();

        return Math.sqrt( dx*dx + dy*dy + dz*dz );
    }

    public void write(DataOutput out) throws IOException {
        out.writeFloat(x);
        out.writeFloat(y);
        out.writeFloat(z);
    }

    public void readFields(DataInput in) throws IOException {
        x = in.readFloat();
        y = in.readFloat();
        z = in.readFloat();
    }

    public static Point3D read(DataInput in) throws IOException {
        Point3D p = new Point3D();
        p.readFields(in);
        return p;
    }

    public String toString() {
        return String.format("%f,%f,%f",x,y,z);
    }

    public float get(int i) {
        return ( i == 0 ) ? x : ( i == 1 ) ? y : z;
    }

	@Override
	public int arity() {
		return 3;
	}

	@Override
	public double getDouble(int i) {
		if ( i == 0 ) return x;
		if ( i == 1 ) return y;
		return z;
	}

	@Override
	public float getFloat(int i) {
		if ( i == 0 ) return x;
		if ( i == 1 ) return y;
		return z;
	}

	@Override
	public int getInt(int i) {
		throw new UnsupportedOperationException();
	}

	@Override
	public long getLong(int i) {
		throw new UnsupportedOperationException();
	}

	@Override
	public String getString(int i) {
		throw new UnsupportedOperationException();
	}

	@Override
	public Type getType(int i) {
		return Type.FLOAT;
	}

	@Override
	public Object getValue(int i) {
		return getFloat(i);
	}

	@Override
	public boolean equals(ITuple o) {
		if ( o instanceof Point3D )
			return equals((Point3D)o);
		if ( o.arity() != 3 ) return false;
		return x == o.getFloat(0) && y == o.getFloat(1) && z == o.getFloat(2);
	}
	
	public boolean equals(Point3D o) {
		return x == o.x && y == o.y && z == o.z;
	}
}
